﻿#include <opencv2/opencv.hpp>          // OpenCV核心库
#include <opencv2/ximgproc.hpp>        // OpenCV扩展模块，包含超像素等高级算法
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;
using namespace cv;
using namespace cv::ximgproc;         // ximgproc命名空间，超像素相关类和函数都在这里

// 用超像素均值颜色填充图像
void colour_with_cluster_means(Mat& image, const Ptr<SuperpixelSLIC>& slic) {
    Mat labels;                       // 存放每个像素对应的超像素标签的矩阵
    slic->getLabels(labels);          // 从分割器中获取标签

    const int num_superpixels = slic->getNumberOfSuperpixels();  // 获取超像素数量
    vector<Vec3d> colors(num_superpixels, Vec3d(0, 0, 0));       // 用double存储每个超像素的BGR颜色累积和
    vector<int> counts(num_superpixels, 0);                      // 每个超像素内像素个数统计

    // 遍历标签矩阵，累加对应超像素内所有像素的颜色值
    for (int y = 0; y < labels.rows; y++) {
        for (int x = 0; x < labels.cols; x++) {
            int label = labels.at<int>(y, x);         // 当前像素所属的超像素标签
            Vec3b color = image.at<Vec3b>(y, x);      // 当前像素的BGR颜色
            colors[label][0] += color[0];             // 累加蓝色通道
            colors[label][1] += color[1];             // 累加绿色通道
            colors[label][2] += color[2];             // 累加红色通道
            counts[label]++;                          // 该超像素像素计数加一
        }
    }

    // 计算每个超像素的平均颜色（累积和除以像素数）
    for (int i = 0; i < num_superpixels; i++) {
        if (counts[i] > 0) {
            colors[i] /= counts[i];
        }
    }

    // 用计算得到的平均颜色替换图像中对应超像素区域的像素颜色
    for (int y = 0; y < labels.rows; y++) {
        for (int x = 0; x < labels.cols; x++) {
            int label = labels.at<int>(y, x);
            image.at<Vec3b>(y, x) = Vec3b(
                    saturate_cast<uchar>(colors[label][0]),  // 防止溢出，强制转换到0-255范围
                    saturate_cast<uchar>(colors[label][1]),
                    saturate_cast<uchar>(colors[label][2])
            );
        }
    }
}

// 在图像上画超像素轮廓
void display_contours(Mat& image, const Ptr<SuperpixelSLIC>& slic, const Scalar& color) {
    Mat mask;                              // 用来存放轮廓掩码
    slic->getLabelContourMask(mask, true); // 获取超像素轮廓掩码，true表示绘制粗轮廓
    image.setTo(color, mask);              // 把轮廓掩码对应位置的像素设置为指定颜色
}

// 显示每个超像素的中心点
void display_center_grid(Mat& image, const Ptr<SuperpixelSLIC>& slic, const Scalar& color) {
    Mat labels;
    slic->getLabels(labels);               // 获取超像素标签矩阵
    const int num_superpixels = slic->getNumberOfSuperpixels();

    vector<Point2d> sums(num_superpixels, Point2d(0, 0));   // 累加每个超像素内所有像素坐标，用于计算中心点
    vector<int> counts(num_superpixels, 0);                // 统计每个超像素的像素数量

    // 遍历所有像素，统计各超像素内像素坐标和数量
    for (int y = 0; y < labels.rows; y++) {
        for (int x = 0; x < labels.cols; x++) {
            int label = labels.at<int>(y, x);
            sums[label] += Point2d(x, y);  // 累加坐标
            counts[label]++;
        }
    }

    // 计算每个超像素中心点并绘制小圆点
    for (int i = 0; i < num_superpixels; i++) {
        if (counts[i] == 0) continue;   // 防止除0
        Point center(cvRound(sums[i].x / counts[i]), cvRound(sums[i].y / counts[i])); // 计算中心坐标，四舍五入
        circle(image, center, 3, color, -1);  // 绘制填充圆，半径3
    }
}

int main() {
    // 读取图像文件
    Mat image = imread("H:/DWORKPLACE/CWork/opencv/testimages/demo1.jpg");
    if (image.empty()) {
        cerr << "Error: 无法读取图片 '1.png'" << endl;   // 打印错误信息
        return -1;
    }

    // 如果图像宽或高超过500像素，则缩小为原来的一半，循环执行，直到尺寸合理
    while (image.cols > 500 || image.rows > 500) {
        resize(image, image, Size(image.cols / 2, image.rows / 2));
    }

    // 创建 SLIC 超像素分割器，SLICO模式，区域大小20，权重10.0
    Ptr<SuperpixelSLIC> slic = createSuperpixelSLIC(image, SLICO, 10, 10.0);
    if (!slic) {
        cerr << "Error: 创建SuperpixelSLIC失败" << endl;
        return -1;
    }

    slic->iterate(10);                  // 迭代10次进行超像素分割
    slic->enforceLabelConnectivity();  // 连接超像素标签，消除噪点超像素

    Mat result = image.clone();         // 复制一份原图用于后续处理

    // 用超像素均值颜色填充图像
    colour_with_cluster_means(result, slic);

    // 叠加超像素轮廓，颜色为红色(BGR:0,0,255)
    display_contours(result, slic, Scalar(0, 0, 255));

    // 显示超像素中心点，颜色为蓝色(BGR:255,0,0)
    display_center_grid(result, slic, Scalar(255, 0, 0));

    // 显示原图窗口
    imshow("原图", image);
    // 显示处理后的结果窗口
    imshow("超像素处理结果", result);

    waitKey(0);    // 等待按键，防止窗口关闭
    return 0;
}
